package com.aw.puzzle.dropboxdiet;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * User: gmc
 * Date: 29/01/11
 */
public class Algorithm {
    List<Activity> smallList;
    List<Activity> bigList;

    public void setAllActivities(List<Activity> allActivities) {
        List<Activity> positiveActivites = new ArrayList();
        List<Activity> negativeActivites = new ArrayList();
        for (Activity activity : allActivities) {
            boolean incrementCalories = activity.getCalorieValue() >= 0;
            if (incrementCalories) {
                negativeActivites.add(activity);
            } else {
                positiveActivites.add(activity);
            }
        }
        Collections.sort(positiveActivites);
        Collections.sort(negativeActivites);
        recalculateSmallAndBigList(positiveActivites, negativeActivites);
    }

    private void recalculateSmallAndBigList() {
        recalculateSmallAndBigList(smallList,bigList);
    }

    private void recalculateSmallAndBigList(List<Activity> activities1, List<Activity> activities2) {
        if (activities1.size() > activities2.size()) {
            smallList = activities2;
            bigList = activities1;
        } else {
            smallList = activities1;
            bigList = activities2;
        }
    }

    public List<ActivityGroup> getActivityGroupsThatSumZeroCalories() {
        SequentialGroupProvider actGroupProvider = new SequentialGroupProvider(smallList);
        List<ActivityGroup> activityGroups = new ArrayList();
        ActivityGroup activityGroupToFind = actGroupProvider.getNextGroup();
        CombinationSet combSetInitial = null;
        while (activityGroupToFind != null) {
            SearchResult searchResult = search(activityGroupToFind, bigList, combSetInitial);
            if (searchResult.equivalentGroupWasFound()) {
                ActivityGroup equivalentGroup = searchResult.getEquivalentGroup();
                activityGroups.add(ActivityGroup.union(activityGroupToFind, equivalentGroup));
                smallList.removeAll(activityGroupToFind.getActivities());
                bigList.removeAll(equivalentGroup.getActivities());
                recalculateSmallAndBigList();
                actGroupProvider.refresh(smallList);
                combSetInitial = null;
                activityGroupToFind = actGroupProvider.getNextGroup();
            } else {
                int lastValue = activityGroupToFind.getValue();
                if (searchResult.groupToFindWasGreaterThanAllElements()) {
                    activityGroupToFind = actGroupProvider.getNextGroupWithValueLessThan(lastValue);
                } else {
                    activityGroupToFind = actGroupProvider.getNextGroup();
                    combSetInitial = searchResult.getFirstCombSetGreater();
                    if (combSetInitial != null && activityGroupToFind != null) {
                        if (activityGroupToFind.getValue() < lastValue) {
                            combSetInitial = null;
                        }
                    }
                }
            }
        }
        return activityGroups;
    }



    public SearchResult search(ActivityGroup groupToFind, List<Activity> list, CombinationSet combSetInitial) {
        ActivityGroup equivalentGroup = null;
        int activitiesXGroup = 1;
        CombinationSetManager combSetMgr = getCombinationSetManager(list, activitiesXGroup, combSetInitial);
        CombinationSet firstCombSetGreater = null;
        while (combSetMgr != null) {
            equivalentGroup = combSetMgr.searchGroupWithTheSameValueOf(groupToFind);
            if (equivalentGroup == null && combSetMgr.isNeededToContinueSearching()) {
                if (firstCombSetGreater == null) {
                    firstCombSetGreater = combSetMgr.getFirstCombSetGreater();
                }
                activitiesXGroup++;
                combSetMgr = getCombinationSetManager(list, activitiesXGroup);
            } else {
                break;
            }
        }
        SearchResult searchResult = new SearchResult();
        searchResult.setFirstCombSetGreater(firstCombSetGreater);
        searchResult.setEquivalentGroup(equivalentGroup);
        searchResult.setLastCombinationSetManager(combSetMgr);
        return searchResult;
    }

    private CombinationSetManager getCombinationSetManager(List<Activity> list, int activitiesXGroup) {
        return getCombinationSetManager(list, activitiesXGroup, null);
    }

    private CombinationSetManager getCombinationSetManager(List<Activity> list, int activitiesXGroup, CombinationSet combSetInitial) {
        if (activitiesXGroup > list.size()) {
            return null;
        }
        CombinationSetManager combinationSetManager = new CombinationSetManager(activitiesXGroup, list);
        combinationSetManager.setCombSetInitial(combSetInitial);
        return combinationSetManager;
    }
}
